﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
#region using for special implements
using Com.ProjectA.Utility;
using Com.ProjectA.DAO;
#endregion using for special implements

namespace Com.ProjectA.BusinessLogic
{
    public class BLGenealogic
    {
        /// <summary>
        /// Find The Generation Rank Of A Person From Person Code
        /// <para>Caution: Begin is 1st generation. Return 0 is invalid</para>
        /// <para>strPerCd: Person Code</para>
        /// <para>return: The generation rank of this person</para>
        /// </summary>
        /// <param name="strPerCd">Person Code</param>
        /// <returns>The generation rank of this person</returns>
        public static int FindGenRankOfPerCd(string strPerCd)
        {
            #region Declare local varibles
            int intNth = 0;
            #endregion Declare local variables
            try
            {
                #region Validation
                if (String.IsNullOrWhiteSpace(strPerCd))
                {
                    return 0;
                }
                #endregion Validation
                if (strPerCd.Length == 2) // The first generation
                {
                    return 1;
                }
                intNth = (strPerCd.Length - 2) / 6 + 1;
                return intNth;
            }
            catch (Exception ex)
            {
                return 0;
            }
        }
        /// <summary>
        /// Find The generation rank from person code
        /// <para>strPerCd: Person Code</para>
        /// <para>intPeriod: The number of Previous/Next generation</para>
        /// <para>isDescendant: False - find descendant generation rank, true - otherwise. Default is false</para>
        /// <para>The generation rank</para>
        /// </summary>
        /// <param name="strPerCd">Person Code</param>
        /// <param name="intPeriod">The number of Previous/Next generation</param>
        /// <param name="isDescendant">False - find descendant generation rank, true - otherwise. Default is false</param>
        /// <returns>The generation rank</returns>
        public static int FindGenRankFromPerCd(string strPerCd, int intPeriod, bool isDescendant = false)
        {
            int intResult = 0;
            try
            {
                // Get the current generation rank
                intResult = FindGenRankOfPerCd(strPerCd);
                #region Validation
                if (intResult == 0)
                {
                    return 0;
                }
                // If finding ancester generation, period must be less than current generation rank
                if (!isDescendant && intPeriod >= intResult)
                {
                    return 0;
                }
                #endregion Validation
                if (isDescendant)
                {
                    intResult = intResult + intPeriod;
                }
                else
                {
                    intResult = intResult - intPeriod;
                }
                return intResult;
            }
            catch (Exception ex)
            {
                return 0;
            }
        }
        
        /// <summary>
        /// Check the (x)father - child relationship between 2 person
        /// <para>strPerCd: Current person code</para>
        /// <para>strXPerCd: The person code we are checking</para>
        /// <para>intPreviousPeriod: The previous generation rank we are checking</para>
        /// <para>return: bool</para>
        /// </summary>
        /// <param name="strPerCd">Current person code</param>
        /// <param name="strXPerCd">The person code we are checking</param>
        /// <param name="intPreviousPeriod">The previous generation rank we are checking</param>
        /// <returns>bool</returns>
        public static bool IsXFather(string strPerCd, string strXPerCd, int intPreviousPeriod)
        {
            #region Declare local variables
            int intCurrentGenRank = 0;
            int intXGenRank = 0;
            #endregion Declare local variables
            try
            {
                #region Validation
                if (String.IsNullOrWhiteSpace(strPerCd) || String.IsNullOrWhiteSpace(strXPerCd))
                {
                    return false;
                }
                intCurrentGenRank = FindGenRankOfPerCd(strPerCd);
                intXGenRank = FindGenRankOfPerCd(strXPerCd);
                // Current generation rank must be not the first one and more than (>) X generation rank
                if (intCurrentGenRank == 1 || intXGenRank >= intCurrentGenRank || intCurrentGenRank != intXGenRank + intPreviousPeriod)
                {
                    return false;
                }
                #endregion Validation
                // Find matched person code
                //RegexUtil regexUtil = new RegexUtil(strXPerCd, System.Text.RegularExpressions.RegexOptions.ExplicitCapture);
                //string strMatched = regexUtil.FindMatchedString(strPerCd);
                string strMatched = strPerCd.Substring(0, (intCurrentGenRank - intPreviousPeriod - 1) * 6 + 2);
                if (!strXPerCd.Equals(strMatched))
                {
                    return false;
                }
                return true;
            }
            catch (Exception ex)
            {
                return false;
            }
        }

        /// <summary>
        /// Check the (x)father - child relationship between 2 person
        /// <para>strPerCd: Current person code</para>
        /// <para>strXPerCd: The person code we are checking</para>
        /// <para>intNextPeriod: The next generation rank we are checking</para>
        /// <para>return: bool</para>
        /// </summary>
        /// <param name="strPerCd">Current person code</param>
        /// <param name="strXPerCd">The person code we are checking</param>
        /// <param name="intNextPeriod">The next generation rank we are checking</param>
        /// <returns>bool</returns>
        public static bool IsXDescendant(string strPerCd, string strXPerCd, int intNextPeriod)
        {
            #region Declare local variables
            int intCurrentGenRank = 0;
            int intXGenRank = 0;
            #endregion Declare local variables
            try
            {
                #region Validation
                if (String.IsNullOrWhiteSpace(strPerCd) || String.IsNullOrWhiteSpace(strXPerCd))
                {
                    return false;
                }
                intCurrentGenRank = FindGenRankOfPerCd(strPerCd);
                intXGenRank = FindGenRankOfPerCd(strXPerCd);
                // Current generation rank must be less than (<) X generation rank
                if (intCurrentGenRank >= intXGenRank || intCurrentGenRank != intXGenRank - intNextPeriod)
                {
                    return false;
                }
                #endregion Validation
                // Find matched person code
                //RegexUtil regexUtil = new RegexUtil(strPerCd, RegexOptions.ExplicitCapture);
                //string strMatched = regexUtil.FindMatchedString(strXPerCd);
                string strMatched = strXPerCd.Substring(0, ((intXGenRank - 1 - intNextPeriod) * 6) + 2);
                if (!strPerCd.Equals(strMatched))
                {
                    return false;
                }
                return true;
            }
            catch (Exception ex)
            {
                return false;
            }
        }

        #region Tim anh em, con chu, con bac
        /// <summary>
        /// Get X Father Code Of A Person Code With X Generation Rank
        /// <para>strPerCd: Person Code</para>
        /// <para>intXGenRank: X Generation Rank</para>
        /// <para>return: X Father Code String. Caution: It can be null. If Generation Rank Of This Person Is 2, X Gen Rank Must Be 1. At That Time, Father Code Is 01</para>
        /// </summary>
        /// <param name="strPerCd">Person Code</param>
        /// <param name="intXGenRank">X Generation Rank</param>
        /// <returns>X Father Code String. Caution: It can be null. If Generation Rank Of This Person Is 2, X Gen Rank Must Be 1. At That Time, Father Code Is 01</returns>
        public static string GetXFatherCdOfPersonCd(string strPerCd, int intXGenRank)
        {
            #region Declare local variables
            int intGenTemp = 0;
            string strXPerCdTemp = null;
            #endregion Declare local variables
            try
            {
                #region Validation
                intGenTemp = FindGenRankOfPerCd(strPerCd);
                // Dieu kien: khong phai generation dau tien, khong phai generation dang tim kiem la generation hien tai, generation dang tim kiem phai truoc generation nguon
                if (intGenTemp == 1 || 0 >= intXGenRank || intXGenRank >= intGenTemp)
                {
                    return null;
                }
                #endregion Validation
                // Get X person code string
                if (intGenTemp == 2)
                {
                    return "01";
                }
                strXPerCdTemp = strPerCd.Substring(0, intXGenRank * 6 + 2);
                return strXPerCdTemp;
            }
            catch (Exception ex)
            {
                return null;
            }
        }
        /// <summary>
        /// Get Mother Code Of Person Cd
        /// </summary>
        /// <param name="strPerCd">Person Code</param>
        /// <returns>Mother Code. Caution: Can be null</returns>
        public static string GetMotherCdOfPersonCd(string strPerCd)
        {
            #region Declare local variables
            int intGenRank = 0;
            string strResult = null;
            #endregion Declare local variables
            try
            {
                #region Validation
                if (String.IsNullOrWhiteSpace(strPerCd))
                {
                    return null;
                }
                intGenRank = FindGenRankOfPerCd(strPerCd);
                if (intGenRank == 0)
                {
                    return null;
                }
                #endregion Validation
                if (intGenRank == 1)
                {
                    return "01";
                }
                // Get YYY (mother code - information)
                strResult = strPerCd.Substring((intGenRank - 2) * 6 + 2, strPerCd.Length - 3);
                return strResult;
            }
            catch (Exception ex)
            {
                return null;
            }
        }

        /// <summary>
        /// Check Is Older/Younger Brother From 2 Person Code (Might Be Whether The Same Or Different Mother - Mother In Law)
        /// <para>strPerCdSource: Person Code Source</para>
        /// <para>strPerCdSearch: Person Code Target (is being checked)</para>
        /// <para>isGetAll: Get All Brother Without Distinguish Younger/Older Brother. Default is distinguishable - false</para>
        /// <para>isYounger: false - older, true - younger</para>
        /// <para>isCheckMotherInLaw: Distinguish Whether Brother Mother In Law Or Not. Default is sibling</para>
        /// <para>return: true - found, false - not found</para>
        /// </summary>
        /// <param name="strPerCdSource">Person Code Source</param>
        /// <param name="strPerCdSearch">Person Code Target (is being checked)</param>
        /// <param name="isGetAll">Get All Brother Without Distinguish Younger/Older Brother. Default is distinguishable - false</param>
        /// <param name="isYounger">false - older, true - younger. Default is younger - false</param>
        /// <param name="kindOfBrother">Distinguish Whether Brother Mother In Law Or Not. Default is sibling</param>
        /// <returns>true - found, false - not found</returns>
        public static bool CheckIsBrother(string strPerCdSource, string strPerCdSearch, bool isGetAll = false, bool isYounger = false, Constants.KindOfBrother kindOfBrother = Constants.KindOfBrother.sibling)
        {
            #region Declare local varibles
            int intNthPerSource = 0;
            int intNthPerSearch = 0;
            string strAncesterCdSourceTemp = null;
            string strAncesterCdSearchTemp = null;
            string strMomCdSourceTemp = null;
            string strMomCdSeachTemp = null;
            #endregion Declare local varibles
            try
            {
                #region Validation
                if (String.IsNullOrWhiteSpace(strPerCdSearch) || String.IsNullOrWhiteSpace(strPerCdSource))
                {
                    return false;
                }
                if (strPerCdSource.Length != strPerCdSearch.Length)
                {
                    return false;
                }
                // Get father code of this person
                strAncesterCdSourceTemp = GetXFatherCdOfPersonCd(strPerCdSource, FindGenRankOfPerCd(strPerCdSource) - 2);
                strAncesterCdSearchTemp = GetXFatherCdOfPersonCd(strPerCdSearch, FindGenRankOfPerCd(strPerCdSearch) - 2);
                if (String.IsNullOrEmpty(strAncesterCdSourceTemp) || String.IsNullOrEmpty(strAncesterCdSearchTemp))
                {
                    return false;
                }
                #endregion Validation
                switch (kindOfBrother)
                {
                    case Constants.KindOfBrother.siblingSameMother:
                        {
                            if (!strAncesterCdSearchTemp.Equals(strAncesterCdSourceTemp))
                            {
                                return false;
                            }
                            break;
                        }
                    case Constants.KindOfBrother.siblingMomInLaw:
                        {
                            if (!strAncesterCdSearchTemp.Equals(strAncesterCdSourceTemp))
                            {
                                return false;
                            }
                            // Get YYY string from person source and person search
                            strMomCdSeachTemp = GetMotherCdOfPersonCd(strPerCdSearch);
                            strMomCdSourceTemp = GetMotherCdOfPersonCd(strPerCdSource);
                            if (strMomCdSourceTemp == null || strMomCdSeachTemp == null)
                            {
                                return false;
                            }
                            // Mom Code Search Must Be Different To Mom Code Source
                            if (strMomCdSeachTemp.Equals(strMomCdSourceTemp))
                            {
                                return false;
                            }
                            break;
                        }
                    case Constants.KindOfBrother.cousin:
                        {
                            break;
                        }
                    case Constants.KindOfBrother.siblingDadInLaw:
                        {
                            break;
                        }
                    default:
                        {
                            if (!strAncesterCdSearchTemp.Equals(strAncesterCdSourceTemp))
                            {
                                return false;
                            }
                            break;
                        }
                }
                if (isGetAll) // No distinguish younger/older
                {
                    return true;
                }
                intNthPerSource = Convert.ToInt32(strPerCdSource.Substring(strPerCdSource.Length - 4));
                intNthPerSearch = Convert.ToInt32(strPerCdSearch.Substring(strPerCdSearch.Length - 4));
                if (isYounger)
                {
                    if (intNthPerSearch > intNthPerSource)
                    {
                        return true;
                    }
                    else
                    {
                        return false;
                    }
                }
                else
                {
                    if (intNthPerSource > intNthPerSearch)
                    {
                        return true;
                    }
                    else
                    {
                        return false;
                    }
                }
            }
            catch (Exception ex)
            {
                return false;
            }
        }
        /// <summary>
        /// Get All Brothers (Might Be Whether The Same Or Different Mother) From A Person
        /// </summary>
        /// <param name="lsPersonSource">List of Person Wants To Find</param>
        /// <param name="personSource">DAOPerson</param>
        /// <returns>List Of Person (DAOPerson)</returns>
        public static List<DAOPerson> GetAllBrothersOfPerson(List<DAOPerson> lsPersonSource, DAOPerson personSource)
        {
            #region Declare local variables
            List<DAOPerson> lsPersonResult = null;
            #endregion Declare local variables
            try
            {
                if (lsPersonSource != null && lsPersonSource.Count > 0 && personSource != null && !String.IsNullOrWhiteSpace(personSource.person_code))
                {
                    lsPersonResult = lsPersonSource.FindAll(x => CheckIsBrother(personSource.person_code
                                                                                , String.IsNullOrWhiteSpace(x.person_code) ? null : x.person_code
                                                                                , true));
                }
                return lsPersonResult;
            }
            catch (Exception ex)
            {
                return null;
            }
        }
        #endregion Tim anh em, con chu, con bac
    }
}
